<?php
/**
 * douban.com API v2
 *
 * PHP version 5
 *
 * LICENSE:
 *
 * Copyright (c) 2012, sink <sink.cup@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *    * The names of the authors may not be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @category douban
 * @package  Douban_Apiv2
 * @author   sink <sink.cup@gmail.com>
 * @license  http://opensource.org/licenses/bsd-license.php New BSD License
 * @version  SVN: $Id: Request2.php 324936 2012-04-07 07:49:03Z avb $
 * @link     http://pear.php.net/package/Douban_Apiv2/
 */

/**
 * HTTP_Request2 package
 */
require_once 'HTTP/Request2.php';

class Douban_Apiv2
{
    /**
     * Configuration parameters
     * @var  array
     * @see  setConfig()
     */
    protected $api_conf = array(
        'get_me'         => 'https://api.douban.com/v2/user/~me',
        'get_movie'         => 'https://api.douban.com/v2/movie/',
        'get_token'         => 'https://www.douban.com/service/auth2/token',
    );

    protected $app_conf;

    protected $format_conf = array(
        'movie' => array(
        ),
        'token' => array(
        ),
        'user' => array(
        ),
    );

    protected $http;

    protected $user;

    /**
     *
     * @param array $app_conf 在 http://developers.douban.com/apikey/ 看到的api_key和secret  比如 array(
     *          'api_key' => xxx,
     *          'secret'  => ooo,
     *      )
     * @param array $user 当前授权用户的token，比如 array(
     *          'access_token'  => xxx,
     *          'refresh_token' => ooo,
     *      )
     */
    public function __construct($app_conf, $user = array(), $format_conf = array())
    {
        $this->app_conf = $app_conf;
        $this->http     = new HTTP_Request2();
        $this->setUser($user);
        $this->setFormatConf($format_conf);
    }
    
    private function format($data, $format)
    {
        if(empty($format)) {
            return $data;
        }
        foreach($format as $k=>$v) {
            $data[$v] = $data[$k];
            unset($data[$k]);
        }
        return $data;
    }

    /**
     * 需要登录：是
     * 获取当前授权用户信息
     * http://developers.douban.com/wiki/?title=user_v2#get_me
     *
     * @param  string $code 跳回redirect_uri时带的code数据
     *
     * @return array 比如 array(
     *      'loc_id' => '108296',
     *      'name' => '已注销',
     *      'created' => '2006-10-05 15:47:27',
     *      'loc_name' => '上海',
     *      'avatar' => 'http://img3.douban.com/icon/u1274827-2.jpg',
     *      'uid' => 'blackegg',
     *      'alt' => 'http://www.douban.com/people/blackegg/',
     *      'id' => '1274827',
     *      'desc' => 'CCN初恋寻初恋，寻爱看电影的媳妇一枚，准备买房啦^o^',
     *  )
     * @throws Douban_Apiv2_Exception
     */
    public function getMe()
    {
        $this->http->setUrl($this->api_conf['get_me']);
        $this->http->setMethod(HTTP_Request2::METHOD_GET);
        try {
            $r = $this->http->send();
            $tmp = json_decode($r->getBody(), true);
        } catch (Exception $e) {
            throw new Exception(); //@todo Douban_Apiv2_Exception
        }
        if(isset($tmp['id'])) {
            return $this->format($tmp, $this->format_conf['user']);
        } else {
            var_dump($tmp);
            throw new Exception(); //@todo Douban_Apiv2_Exception
        }
    }


    /**
     * 需要登录：否
     * 获取电影信息
     * http://developers.douban.com/wiki/?title=movie_v2&_r=280929636176372089#get_movie
     *
     * @param  string $code 跳回redirect_uri时带的code数据
     *
     * @return array 比如 array (
     *     'rating' => 
     *     array (
     *       'max' => 10,
     *       'average' => '8.9',
     *       'numRaters' => 172096,
     *       'min' => 0,
     *     ),
     *     'author' => 
     *     array (
     *       0 => 
     *       array (
     *         'name' => '刘镇伟',
     *       ),
     *     ),
     *     'alt_title' => '大话西游之大圣娶亲',
     *     'image' => 'http://img3.douban.com/spic/s1311495.jpg',
     *     'title' => '西游记大结局之仙履奇缘',
     *     'mobile_link' => 'http://m.douban.com/movie/subject/1292213/',
     *     'summary' => '至尊宝（周星驰）被月光宝盒带回到五百年前，遇见紫霞仙子（朱茵），被对方打上烙印成为对方的人，并发觉自己已变成孙悟空。
     *   紫霞与青霞（朱茵）本是如来佛祖座前日月神灯的灯芯（白天是紫霞，晚上是青霞），二人虽然同一肉身却仇恨颇深，因此紫霞立下誓言，谁能拔出她手中的紫青宝剑，谁就是她的意中人。紫青宝剑被至尊宝于不经意间拔出，紫霞决定以身相许，却遭一心记挂白晶晶（莫文蔚）的至尊宝拒绝。后牛魔王救下迷失在沙漠中的紫霞，并逼紫霞与他成婚，关键时刻，至尊宝现身。',
     *     'attrs' => 
     *     array (
     *       'pubdate' => 
     *       array (
     *         0 => '1995-02-04(香港)',
     *       ),
     *       'language' => 
     *       array (
     *         0 => '粤语',
     *         1 => '普通话',
     *       ),
     *       'title' => 
     *       array (
     *         0 => '西游记大结局之仙履奇缘',
     *       ),
     *       'country' => 
     *       array (
     *         0 => '中国大陆',
     *         1 => '香港',
     *       ),
     *       'writer' => 
     *       array (
     *         0 => '刘镇伟 Jeffrey Lau',
     *       ),
     *       'director' => 
     *       array (
     *         0 => '刘镇伟',
     *       ),
     *       'cast' => 
     *       array (
     *         0 => '周星驰 Stephen Chow',
     *         1 => '朱茵 Athena Chu',
     *         2 => '莫文蔚 Karen Mok',
     *         3 => '吴孟达 Man Tat Ng',
     *         4 => '罗家英 Kar-Ying Law',
     *         5 => '蔡少芬 Ada Choi',
     *         6 => '蓝洁瑛 Kit Ying Lam',
     *         7 => '刘镇伟 Jeffrey Lau',
     *       ),
     *       'movie_duration' => 
     *       array (
     *         0 => '95分钟',
     *       ),
     *       'year' => 
     *       array (
     *         0 => '1994',
     *       ),
     *       'movie_type' => 
     *       array (
     *         0 => '动作',
     *         1 => '冒险',
     *         2 => '喜剧',
     *         3 => '奇幻',
     *         4 => '爱情',
     *       ),
     *     ),
     *     'alt' => 'http://movie.douban.com/movie/1292213',
     *     'id' => 'http://api.douban.com/movie/1292213',
     *     'tags' => 
     *     array (
     *       0 => 
     *       array (
     *         'count' => 23824,
     *         'name' => '喜剧',
     *       ),
     *       1 => 
     *       array (
     *         'count' => 22629,
     *         'name' => '经典',
     *       ),
     *       2 => 
     *       array (
     *         'count' => 17311,
     *         'name' => '香港',
     *       ),
     *     ),
     *  )
     * @throws Douban_Apiv2_Exception
     */
    public function getMovie($id)
    {
        $this->http->setUrl($this->api_conf['get_movie'] . $id);
        $this->http->setMethod(HTTP_Request2::METHOD_GET);
        try {
            $r = $this->http->send();
            $tmp = json_decode($r->getBody(), true);
        } catch (Exception $e) {
            throw new Exception(); //@todo Douban_Apiv2_Exception
        }
        if(isset($tmp['title'])) {
            if(!isset($tmp['attrs']['year'][0]) && isset($tmp['attrs']['pubdate'][0])) {
                $tmp['attrs']['year'][0] = substr($tmp['attrs']['pubdate'][0], 0, 4);
            }
            return $this->format($tmp, $this->format_conf['movie']);
        } else {
            var_dump($tmp);
            throw new Exception(); //@todo Douban_Apiv2_Exception
        }
    }

    /**
     * 需要登录：否
     * 获取 access_token, refresh_token
     *
     * @param  string $code 跳回redirect_uri时带的code数据
     *
     * @return array 比如 array(
     *          'access_token'  => xxx,
     *          'refresh_token' => ooo,
     *      )
     * @throws Douban_Apiv2_Exception
     */
    public function getToken($code)
    {
        $this->http->setUrl($this->api_conf['get_token']);
        $this->http->setMethod(HTTP_Request2::METHOD_POST);
        $data = array(
            'client_id' => $this->app_conf['api_key'],
            'client_secret' => $this->app_conf['secret'],
            'redirect_uri' => $this->app_conf['redirect_uri'],
            'grant_type' => 'authorization_code',
            'code' => $code,
        );
        $this->http->addPostParameter($data);
        try {
            $r = $this->http->send();
            $tmp = json_decode($r->getBody(), true);
        } catch (Exception $e) {
            throw new Exception(); //@todo Douban_Apiv2_Exception
        }
        if(isset($tmp['access_token'])) {
            return $this->format($tmp, $this->format_conf['token']);
        } else {
            var_dump($tmp);
            throw new Exception(); //@todo Douban_Apiv2_Exception
        }
    }

    public function setFormatConf($format_conf)
    {
        if(empty($format_conf)) {
            return true;
        }
        foreach($format_conf as $k=>$v) {
            $this->format_conf[$k] = $v;
        }
        return true;
    }

    /**
     * Header格式为"Authorization: Bearer access_token"，其中Bearer后面有一个空格 
     * http://developers.douban.com/wiki/?title=connect
     */
    public function setUser($user)
    {
        $this->user = $user;
        if(isset($this->user['access_token'])) {
            $header = array(
                'Authorization' => 'Bearer ' . $this->user['access_token'],
            );
            $this->http->setHeader($header);
        }
        return true;
    }
}
?>
